/**
 * @file netlist.h
 * @brief Function definitions to read netlist files, and write them back.
 *
 * This file contains all the function definitions suggested in the assignment file.
 * Type definitions are included as well, but were given by the assignment.
 */

#ifndef NETLIST_H_
#define NETLIST_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "hash.h"


#define LINE_BUF_SIZE 200
#define NAME_BUF_SIZE 20
// INSERT your own comments
/**
 * @brief Get the GATE of a circuit item.
 */
#define GET_GATE(x)	(x->cir_type.circuit_gate)

/**
 * @brief Get the WIRE of a circuit item.
 */
#define GET_WIRE(x) 	(x->cir_type.circuit_wire)

/**
 * @brief Define an enum for the possible gate types.
 */
typedef enum {Not, And, Or, Xor, Xnor, Nand, Nor} gate_type;
/**
 * @brief Define an enum for the types of circuit elements. (Gate or Wire)
 */
typedef enum {Gate, Wire} circuit_type;

/**
 * @brief Struct defining a wire element of the circuit.
 */
typedef struct s_wire{
  struct circuit_item *in; /*!< */

  int no_outputs; /*!< */
  struct circuit_item **out; /*!< Array of pointers of size out_connections.*/
} s_wire;

/**
 * @brief Struct defining the information necessary for each gate.
 */
typedef struct s_gate{
  gate_type type;		/**< Type of the gate (see gate_type) */
  
  int no_inputs;			/**< The number of inputs of the gate*/
  struct circuit_item **in;/*!< Circuit items linked to the input of the gate*/

  struct circuit_item *out;/**< Circuit item linked to the output of the gate*/
} s_gate;

/**
 * @brief Type definition of a circuit item.
 *
 * A circuit item is a general item. Could be a gate or a wire.
 */
typedef struct circuit_item{
  char name[50];			/**< Name of the circuit item. max 50 chars.*/
  circuit_type type;	/**< Type of the circuit. (gate or wire)*/
  
  union{
    s_wire circuit_wire;
    s_gate circuit_gate;
  } cir_type;				/**< The actual item information.*/
} circuit_item;

/**
 * @brief Type definition for the interface structure.
 *
 * The interface is how this circuit connects to the external world.
 */
typedef struct s_interface{
  int no_inputs;			/**< Number of inputs of the circuit */
  circuit_item **inputs;	/**< The input items of the circuit */
  
  int no_outputs;			/**< Number of outputs of the circuit */
  circuit_item **outputs;	/**< The output items of the circuit */
  
} s_interface;

/**
 *
 * @param line
 */
void to_lower_case(char *line);
/**
 *
 * @param fp
 * @param line
 */
void read_line(FILE *fp, char line[]);

/**
 *
 * @param line
 * @return
 */
int isInput(char *line);

/**
 *
 * @param line
 * @return
 */
int isOutput(char *line);

/**
 *
 * @param line
 * @return
 */
int isGate(char *line);

/**
 *
 * @param fp
 * @param no_inputs
 * @param no_outputs
 */
void netlist_statistics(FILE *fp, int *no_inputs, int *no_outputs);

/**
 *
 * @param str
 * @return
 */
gate_type determine_gate_type(char *str);

/**
 *
 * @param table
 * @param table_size
 * @param str
 * @return
 */
circuit_item *get_or_insert_wire_item(node *table[], int table_size, char *str);

/**
 *
 * @param line
 * @param inputs
 * @param wr_index
 * @param table
 * @param table_size
 */
void input_statement(char *line, circuit_item *inputs[], int *wr_index, node *table[], int table_size);

/**
 *
 * @param line
 * @param outputs
 * @param wr_index
 * @param table
 * @param table_size
 */
void output_statement(char *line, circuit_item *outputs[], int *wr_index, node *table[], int table_size);

/**
 *
 * @param line
 * @param table
 * @param table_size
 */
void gate_statement(char *line, node *table[], int table_size);

/**
 *
 * @param line
 * @param id
 * @return
 */
int count_occurences(char line[], char id);

/**
 *
 * @param fp
 * @param interface
 * @param table
 * @param table_size
 */
void read_netlist(FILE *fp, s_interface *interface, node *table[], int table_size);

/**
 *
 * @param fp_out
 * @param interface
 * @param table
 * @param table_size
 */
void write_netlist(FILE *fp_out, s_interface *interface, node *table[], int table_size);

/**
 *
 * @param gate
 * @param line
 * @return
 */
int generate_gate_line(s_gate gate, char *line);

/**
 *
 * @param item
 */
void free_circuititem(circuit_item *item);
#endif /* NETLIST_H_ */
